package vn.edu.saigontech.ncms.model.program;

import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.StringTokenizer;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.hibernate.annotations.OptimisticLockType;

import vn.edu.saigontech.ncms.model.BaseEntity;
import vn.edu.saigontech.ncms.model.bookstore.ItemTitle;
import vn.edu.saigontech.ncms.model.info.Offering;
import vn.edu.saigontech.ncms.model.info.Waiting;
import vn.edu.saigontech.ncms.model.system.Money;
import vn.edu.saigontech.ncms.util.DateUtil;

@Entity
@org.hibernate.annotations.Entity(dynamicInsert = true, dynamicUpdate = true, optimisticLock = OptimisticLockType.ALL)
@Table(name = "ncms_level")
@SuppressWarnings("serial")
public class Level extends BaseEntity {

	@Column(name = "name", nullable = false, unique = true)
	private String name;
	
	@Column(name = "hours")
	private int hours;

	@Column(name = "weeks")
	private int weeks;

	@Embedded
	@AttributeOverrides( { @AttributeOverride(name = "amount", column = @Column(name = "tuition")), })
	private Money tuition;

	@Column(name = "min_score")
	private Double minScore;

	@Column(name = "max_score")
	private Double maxScore;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "program_id", nullable = false)
	private Program program;

	@Column(name = "active")
	private boolean active;

	@Column(name = "sequence")
	private int order;

	@Column(name = "content", length = 4000)
	private String content;

	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "level")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	private Set<Waiting> waitings = new HashSet<Waiting>();

	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "level")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	@OrderBy("startDate desc")
	private Set<Offering> offerings = new HashSet<Offering>();
	
//	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "level")
//	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
//	private Set<ItemTitle> itemTitles;

	@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "levels")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	private Set<ItemTitle> titles;

	public boolean accept(Double score) {
		return score >= this.minScore && score <= this.maxScore;
	}

	@Transient
	public Set<Level> getHigherLevels() {
		Set<Level> result = new LinkedHashSet<Level>();
		for (Level level : this.program.getLevels()) {
			if (level.maxScore > this.maxScore) {
				result.add(level);
			}
		}
		return result;
	}

	@Transient
	public String getCourseName() {
		if ("English for Children".equalsIgnoreCase(this.program.getName())
				|| "English for Teenagers".equalsIgnoreCase(this.program
						.getName())
				|| "General English".equalsIgnoreCase(this.program.getName())) {
			StringTokenizer tokens = new StringTokenizer(this.name);
			String courseName = "";
			while (tokens.hasMoreTokens()) {
				courseName = tokens.nextToken();
			}
			return "Level " + courseName;
		}
		return this.name;
	}

	public boolean contains(Waiting waiting) {
		for (Waiting each : this.waitings) {
			if (each.getStudent().equals(waiting.getStudent()))
				return true;
		}
		return false;
	}

	public String getDocument() {
		StringTokenizer tokens = new StringTokenizer(this.content, "\n\r");
		StringBuffer buffer = new StringBuffer();
		while (tokens.hasMoreTokens()) {
			buffer.append(tokens.nextToken());
			buffer.append("<br/>");
		}
		return buffer.toString();
	}
	
	public boolean getHasOpeningOffering() {
		Date currentDate = DateUtil.newDate();
		int count = 0;
		for (Offering each : offerings) {
			if (each.getEndDate().after(currentDate)) count++;
		}
		return count > 0;
	}

	public boolean isActive() {
		return active;
	}

	public void setActive(boolean active) {
		this.active = active;
	}

	public Double getMaxScore() {
		return maxScore;
	}

	public void setMaxScore(Double maxScore) {
		this.maxScore = maxScore;
	}

	public Double getMinScore() {
		return minScore;
	}

	public void setMinScore(Double minScore) {
		this.minScore = minScore;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Program getProgram() {
		return program;
	}

	public void setProgram(Program program) {
		this.program = program;
	}

	public int getHours() {
		return hours;
	}

	public void setHours(int hours) {
		this.hours = hours;
	}

	public int getWeeks() {
		return weeks;
	}

	public void setWeeks(int weeks) {
		this.weeks = weeks;
	}

	public Money getTuition() {
		return tuition;
	}

	public void setTuition(Money tuition) {
		this.tuition = tuition;
	}

	public Set<Waiting> getWaitings() {
		return waitings;
	}

	public void setWaitings(Set<Waiting> waitings) {
		this.waitings = waitings;
	}

	public int getOrder() {
		return order;
	}

	public void setOrder(int order) {
		this.order = order;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public Set<Offering> getOfferings() {
		return offerings;
	}

	public void setOfferings(Set<Offering> offerings) {
		this.offerings = offerings;
	}

//	public Set<ItemTitle> getItemTitles() {
//		return itemTitles;
//	}
//
//	public void setItemTitles(Set<ItemTitle> itemTitles) {
//		this.itemTitles = itemTitles;
//	}

	public Set<ItemTitle> getTitles() {
		return titles;
	}

	public void setTitles(Set<ItemTitle> titles) {
		this.titles = titles;
	}
}